/*
 * @Author: hanyuanjiao
 * @Date: 2025-07-21 06:52:28
 * @LastEditors: Please set LastEditors
 * @LastEditTime: 2025-08-20 18:31:32
 * @Description: 请填写简介
 */
#include <stdio.h>

#include "kbhit.h"
#include "mem.h"
#include "simu8051.h"
#include "test.h"
#include "tools.h"

void test_instr(char *);
//第0个测试项
// static uint8_t t0;
// 对应于指令:NOP,NOP,NOP,SJMP $
// SJMP $是原地跳转
// test0,手动指定要执行的指令
// nop sjmp
// static uint8_t t0_nop_code[] = {0x00, 0x00, 0x80, 0xFE};
//要测试的hex文件
static char *file_name[] = {
    "hex_code/hex/t00.hex", "hex_code/hex/t0.hex",  "hex_code/hex/t1.hex",  "hex_code/hex/t2.hex",
    "hex_code/hex/t3.hex",  "hex_code/hex/t4.hex",  "hex_code/hex/t5.hex",  "hex_code/hex/t6.hex",
    "hex_code/hex/t7.hex",  "hex_code/hex/t8.hex",  "hex_code/hex/t9.hex",  "hex_code/hex/t10.hex",
    "hex_code/hex/t11.hex", "hex_code/hex/t12.hex", "hex_code/hex/t13.hex", "hex_code/hex/t14.hex",
    "hex_code/hex/t15.hex", "hex_code/hex/t16.hex", "hex_code/hex/t17.hex", "hex_code/hex/t18.hex",
    "hex_code/hex/t20.hex", "hex_code/hex/t21.hex", "hex_code/hex/t22.hex",
};
//测试所有的hex文件
void test_all_hex()
{
    for (int i = 0; i < sizeof(file_name) / sizeof(char *); i++)
    {
        test_instr(file_name[i]);
    }
}
void check_result()
{
    uint16_t addr = 0x600;
    do
    {
        uint8_t  addr0       = simu8051_read(MEM_TYPE_CODE, addr++);
        uint8_t  addr1       = simu8051_read(MEM_TYPE_CODE, addr++);
        uint8_t  data0       = simu8051_read(MEM_TYPE_CODE, addr++);
        uint8_t  data1       = simu8051_read(MEM_TYPE_CODE, addr++);
        uint16_t cmp_addr    = (addr0 << 8) | addr1;
        uint16_t expect_data = (data0 << 8) | data1;
        uint16_t real_data;
        switch (cmp_addr)
        {
        case REG_SP:
            real_data = simu8051_read(MEM_TYPE_SFR, SFR_SP);
            break;
        case REG_A:
            real_data = simu8051_read(MEM_TYPE_SFR, SFR_ACC);
            break;
        case REG_B:
            real_data = simu8051_read(MEM_TYPE_SFR, SFR_B);
            break;
        case REG_PSW:
            real_data = simu8051_read(MEM_TYPE_SFR, SFR_PSW);
            break;
        case REG_PC:
            real_data = simu8051_pc();
            break;
        case REG_DPTR:
            real_data = simu8051_read(MEM_TYPE_SFR, SFR_DPH) << 8;
            real_data |= simu8051_read(MEM_TYPE_SFR, SFR_DPL);
            break;
        case CYCLE:
            real_data = simu8051_cycle();
            break;
        //暂时认为RS1:RS0=00,故r0~r7存放在iram中的0~7中
        case REG_R0:
            real_data = simu8051_read(MEM_TYPE_IRAM, 0);
            break;
        case REG_R1:
            real_data = simu8051_read(MEM_TYPE_IRAM, 1);
            break;
        case REG_R2:
            real_data = simu8051_read(MEM_TYPE_IRAM, 2);
            break;
        case REG_R3:
            real_data = simu8051_read(MEM_TYPE_IRAM, 3);
            break;
        case REG_R4:
            real_data = simu8051_read(MEM_TYPE_IRAM, 4);
            break;
        case REG_R5:
            real_data = simu8051_read(MEM_TYPE_IRAM, 5);
            break;
        case REG_R6:
            real_data = simu8051_read(MEM_TYPE_IRAM, 6);
            break;
        case REG_R7:
            real_data = simu8051_read(MEM_TYPE_IRAM, 7);
            break;
        case REG_END:
            return;
        default:
            real_data = simu8051_read(MEM_TYPE_IRAM, cmp_addr);
            break;
        }
        if (real_data != expect_data)
        {
            printf("test error:addr=0x%x,real=%x,expect=%x\n", cmp_addr, real_data, expect_data);
            exit(-1);
        }
    } while (1);
}
//执行手动制定的指令
void test_instr(char *file_name)
{
    uint16_t pc;
    uint8_t *test_code;
    simu8051_reset();
    //转变测试项目,修改此处
    // test_code = t0_nop_code;
    if (file_name == NULL)
    {
        file_name = "hex_code/t1.hex";
    }
    printf("begin test:%s\n", file_name);
    test_code = simu8051_load_hexfile(file_name);
    if (test_code == NULL)
    {
        printf("load hex file failed:%s\n", file_name);
        exit(-1);
    }
    simu8051_load(test_code);
    do
    {
        instr_t instr;
        pc = simu8051_pc();
        simu8051_fetch_instr(&instr);
        if (instr.info->bytes == 0)
        {
            printf("unknow instruction. opcode=0x%x", instr.opcode);
            exit(-1);
        }
        show_disa(&instr);
        simu8051_exec(&instr);
        simu8051_dump_regs();
    } while (pc != simu8051_pc());
    check_result();
    free(test_code);
    printf("end test!\n");
}

void test_program()
{
    // const char *file_name = "hex_code/hex/t19.hex";
    // const char *file_name = "hex_code/hex/t23.hex";
    // const char *file_name = "hex_code/hex/t24.hex";
    const char *file_name = "hex_code/hex/t25.hex";
    uint8_t    *test_code = simu8051_load_hexfile(file_name);
    if (test_code == NULL)
    {
        printf("load hex file failed:%s\n", file_name);
        exit(-1);
    }
    simu8051_reset();
    simu8051_load(test_code);
    simu8051_run(0, 0);
    free(test_code);
}
int main()
{
    init_keyboard();
    tool_test0();
    // test_memory();
    simu8051_init();
    // test_instr(NULL);
    test_all_hex();
    // test_program();
    close_keyboard();
    return 0;
}

void simu8051_uart_write(char c)
{
    putchar(c);
    //模拟串口发送数据之后中断被触发过程
    simu8051_write(MEM_TYPE_BIT, SFR_SCON_TI, 1);
}
char simu8051_uart_read()
{
    return kbhit() ? getchar() : 0;
}
int simu8051_uart_rx_rdy()
{
    return kbhit();
}
